#ifndef _SERVER_
#define _SERVER_

#include <iostream>
#include <fstream>
#include "SFML/Network.hpp"

#include "ClientCollection.hpp"
#include "LoadingClientCollection.hpp"

#include "Engine.hpp"
#include "Content/Map.hpp"
#include "Networking.hpp"
#include "Content/MapLoader.hpp"
#include "Scripting/Scripting.hpp"
#include "ServerScriptEngine.hpp"
#include "Objects/PlayerManager.hpp"
#include "Objects/ServerEntityManager.hpp"
#include "Objects/ServerRegionManager.hpp"
#include "NetworkHandler.hpp"
#include "Networking/PacketHelper.hpp"

#include "Utilities/StringHelper.hpp"
#include "Utilities/FileLogger.hpp"

using namespace std;
using namespace sf;

class Server:public Scriptable, public Engine {
private:

    /** 
    * Is the server running.
    */
    bool run;

    /** 
    * Udp Listener socket
    */
    UdpSocket socket;

    /** 
    * ClientCollection storing all connected clients.
    */
    ClientCollection clientsList;

    /** 
    * LoadingClientCollection storing all clients that are in the process of connecting to the server.
    */
    LoadingClientCollection loadingClientsList;

    /** 
    * Script engine for the server level.
    */
    ServerScriptEngine sEngine;

    int inPort;
    int maxClients;
    int clientTimeout;

    std::string name;
    std::string url;
  
    void handleConnection();
    void handleTimeouts();

    void handleNewConnection(MessageIterator& iMessage, const sf::IpAddress& address, const unsigned short& port);
    void handleLoadingConnection(MessageIterator& iMessage, const sf::IpAddress& address);
    void handleClientConnection(MessageIterator& iMessage, const sf::IpAddress& address);
    void updateClientQueues();
    virtual void update();

    class ServerTime : public MessageQueue::ServerTime {
    public:
        Clock serverTime;

        virtual uint32_t getTime() {
            return serverTime.getElapsedTime().asMilliseconds();
        }
    };

	/** 
	* MessageQueue for all incoming messages.
	*/
	MessageQueue globalInQueue;

	/** 
	* MessageQueue for outgoing messages to non clients.
	*/
	MessageQueue globalOutQueue;

    /** 
    * The amount of time the server has been running.
    */
    ServerTime time;
    uint32_t lastUpdate;
    uint32_t frameTime;

    /** 
    * Current map.
    */
    Map* map;

	NetworkHandler networkHandler;

    PlayerManager playerManager;
	ServerEntityManager entityManager;
    ServerRegionManager regionManager;
public:
    static Server* instance;

    Server();

    int start();
    void stop();
    void shutdown();
    int startup();

	Character* createEntity(const char* name);

    void disconnectClient(byte client);
    void renameClient(byte client, const char* name);
    void sendAllChatMessage(const char* message);

    static void httpPost(const char* host, const char* addr, const char* msg);

    virtual void bind(lua_State* luaState);
    virtual void push(lua_State* luaState);

    ~Server();
};

#endif